home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Applications / TimGA 1.2.1 / .cp / CGraphDrawing.cp < prev    next >
Encoding:
Text File  |  1997-07-16  |  17.6 KB  |  684 lines  |  [TEXT/CWIE]

  1. // ===========================================================================
  2. //    CGraphDrawing.cp        ©1995-97 Timo Eloranta        All rights reserved.
  3. // ===========================================================================
  4. //    An instance of the CGraphDrawing class represents a single possibility of 
  5. //    drawing the given graph. The population consists of these objects.
  6.  
  7. #include <UException.h>
  8.  
  9. #include "CGraphDrawing.h"
  10. #include "CCrossMemory.h"
  11. #include "MyUtils.h"
  12.  
  13. // ---------------------------------------------------------------------------
  14. //        • CGraphDrawing
  15. //
  16. //          Called by:    CPopulation::Initialize
  17. // ---------------------------------------------------------------------------
  18. //    Constructor.
  19.  
  20. CGraphDrawing::CGraphDrawing()
  21. {
  22.     mEdgeCount = 0;
  23.     mCrossMemo = nil;
  24. }
  25.  
  26. // ---------------------------------------------------------------------------
  27. //        • ~CGraphDrawing
  28. //
  29. //          Called by:    CPopulation::JunkGraphs
  30. // ---------------------------------------------------------------------------
  31. //    Destructor.
  32.  
  33. CGraphDrawing::~CGraphDrawing()
  34. {
  35.     JunkCrossMemory();
  36. }
  37.  
  38. // ---------------------------------------------------------------------------
  39. //        • Initialize
  40. //
  41. //          Called by:    CPopulation::Initialize
  42. // ---------------------------------------------------------------------------
  43.  
  44. void 
  45. CGraphDrawing::Initialize( 
  46.         Int16     inNodeCount,
  47.         Int16     inEdgeCount,
  48.         Int16     inGridSize,
  49.         Boolean    inFirstTime)
  50. {
  51.     mNodes.Initialize( inNodeCount, inGridSize, inFirstTime );
  52.     
  53.     if ( inEdgeCount != mEdgeCount) {
  54.         mEdges.erase( mEdges.begin(), mEdges.end() );
  55.         mEdges.reserve( inEdgeCount );
  56.         
  57.         for ( Int16 theDex = 1; theDex <= inEdgeCount; ++theDex )
  58.             mEdges.push_back( CEdge() );
  59.         
  60.         mEdgeCount = inEdgeCount;
  61.     }
  62.  
  63.     mMemoryIsGarbage    = true;
  64.     mEvaluationNeeded    = true;
  65. }
  66.  
  67. // ---------------------------------------------------------------------------
  68. //        • AddCrossMemory
  69. //
  70. //          Called by:    CPopulation::AddCrossMemories
  71. // ---------------------------------------------------------------------------
  72.  
  73. void
  74. CGraphDrawing::AddCrossMemory()
  75. {
  76.     mCrossMemo = new CCrossMemory( mEdgeCount );
  77.     
  78.     ThrowIfNil_ (mCrossMemo);
  79. }
  80.  
  81. // ---------------------------------------------------------------------------
  82. //        • JunkCrossMemory
  83. //
  84. //          Called by:    CGraphDrawing::~CGraphDrawing
  85. //                        CPopulation::AddCrossMemories
  86. // ---------------------------------------------------------------------------
  87.  
  88. void
  89. CGraphDrawing::JunkCrossMemory()
  90. {
  91.     if ( mCrossMemo ) {
  92.         delete mCrossMemo;
  93.         mCrossMemo = nil;
  94.     }
  95. }
  96.  
  97. // ---------------------------------------------------------------------------
  98. //        • ValidNewEdge
  99. //
  100. //          Called by:    CPopulation::SetUpEdges
  101. // ---------------------------------------------------------------------------
  102.  
  103. Boolean 
  104. CGraphDrawing::ValidNewEdge( 
  105.     Int16 inNodeNbr1, 
  106.     Int16 inNodeNbr2) const
  107. {
  108.     CEdge    theTestEdge;
  109.     
  110.     CNodePtr    theNode1 = mNodes.GetNodePtrByNbr( inNodeNbr1);
  111.     CNodePtr    theNode2 = mNodes.GetNodePtrByNbr( inNodeNbr2);
  112.  
  113.     theTestEdge.Set( theNode1, theNode2);
  114.     
  115.     // Check if we already have this one or not...
  116.     
  117.     EdgeVector::const_iterator    theIter = mEdges.begin();
  118.  
  119.     while ( theIter != mEdges.end() ) {
  120.         if ( *theIter == theTestEdge )
  121.             return false;
  122.         ++theIter;
  123.     }
  124.     return true;
  125. }
  126.  
  127. // ---------------------------------------------------------------------------
  128. //        • SetNewEdge
  129. //
  130. //          Called by:    CPopulation::SetUpEdges
  131. // ---------------------------------------------------------------------------
  132.  
  133. void
  134. CGraphDrawing::SetNewEdge( 
  135.     Int16 inEdgeNbr, 
  136.     Int16 inNodeNbr1,
  137.     Int16 inNodeNbr2)
  138. {
  139.     CNodePtr    theNode1 = mNodes.GetNodePtrByNbr( inNodeNbr1 );
  140.     CNodePtr    theNode2 = mNodes.GetNodePtrByNbr( inNodeNbr2 );
  141.  
  142.     // mEdges is 0-based !! ---> - 1
  143.  
  144.     mEdges[ inEdgeNbr - 1 ].Set( theNode1, theNode2 );
  145. }
  146.  
  147. // ---------------------------------------------------------------------------
  148. //        • Mutate
  149. //
  150. //          Called by:    CPopulation::DoMutate
  151. // ---------------------------------------------------------------------------
  152.  
  153. void
  154. CGraphDrawing::Mutate()
  155. {
  156.     // A random selection for the mutation type
  157.     
  158.     Int16    theMutationType = RangedRdm( 1, 65 );
  159.  
  160.     if ( theMutationType <= 8 ) {
  161.  
  162.         switch ( theMutationType ) {
  163.         
  164.             case 1:     mNodes.SwapRows();
  165.                         mEvaluationNeeded = true;
  166.                         break;
  167.             case 2:     mNodes.SwapCols();
  168.                         mEvaluationNeeded = true;
  169.                         break;
  170.             
  171.             case 3:        mEvaluationNeeded = 
  172.                         mNodes.SwapInRowOrCol(true) || mEvaluationNeeded;
  173.                         break;
  174.             case 4:     mEvaluationNeeded = 
  175.                         mNodes.SwapInRowOrCol(false) || mEvaluationNeeded;
  176.                         break;
  177.             
  178.             case 5:     mEvaluationNeeded = 
  179.                         mNodes.InvertRow() || mEvaluationNeeded;
  180.                         break;
  181.             case 6:     mEvaluationNeeded = 
  182.                         mNodes.InvertPartRow() || mEvaluationNeeded;
  183.                         break;
  184.     
  185.             case 7:     mEvaluationNeeded = 
  186.                         mNodes.InvertCol() || mEvaluationNeeded;
  187.                         break;
  188.             case 8:     mEvaluationNeeded = 
  189.                         mNodes.InvertPartCol() || mEvaluationNeeded;
  190.                         break;
  191.         }
  192.         
  193.     } else 
  194.          if ( theMutationType <= 18 ) {
  195.             mNodes.SingleMutate();
  196.             mEvaluationNeeded = true;
  197.         }
  198.      else                                    
  199.         if ( theMutationType <= 28 ) {        // Edge length preserving
  200.             EdgeMutation( true, false );    // normal edge mutation...
  201.             mEvaluationNeeded = true;
  202.         } 
  203.      else                                    
  204.         if ( theMutationType <= 40 ) {        // Edge length preserving
  205.              mEvaluationNeeded =                // two (2) edge mutation...
  206.              TwoEdgeMutation() || mEvaluationNeeded;
  207.         } 
  208.      else
  209.          if ( theMutationType <= 45 ) {
  210.              mEvaluationNeeded =
  211.              mNodes.TinyMutate() || mEvaluationNeeded;
  212.          }
  213.      else                                    // Edge length preserving
  214.         if ( theMutationType <= 50 ) {         // tiny edge mutation...
  215.             mEvaluationNeeded =
  216.              EdgeMutation( true, true ) || mEvaluationNeeded;
  217.          }
  218.      else
  219.          if ( theMutationType <= 55 ) {
  220.              mNodes.SmallMutate();
  221.             mEvaluationNeeded = true;
  222.          }
  223.      else
  224.         if ( theMutationType <= 60 ) {             
  225.             mEvaluationNeeded =
  226.             mNodes.LargeContMutate() || mEvaluationNeeded;
  227.          }
  228.      else {                                    // Edge length changing
  229.              EdgeMutation( false, false );    // normal edge mutation...
  230.             mEvaluationNeeded = true;
  231.          }
  232. }
  233.  
  234. // ---------------------------------------------------------------------------
  235. //        • EdgeMutation        (PRIVATE)
  236. //
  237. //          Called by:    CGraphDrawing::Mutate
  238. // ---------------------------------------------------------------------------
  239.  
  240. Boolean
  241. CGraphDrawing::EdgeMutation( 
  242.     Boolean inPreserveLength,
  243.     Boolean    inTiny )
  244. {
  245.     CEdge        *theEdge;
  246.     CNodePtr    theNode1, theNode2;
  247.     
  248.     if ( mEdgeCount == 0 ) return false;
  249.     
  250.     Int16    theEdgeIndex = FastRandom( mEdgeCount );
  251.  
  252.     theEdge = &mEdges[ theEdgeIndex ];
  253.     
  254.     theEdge -> GetEdgeNodes( theNode1, theNode2 );
  255.     
  256.     if (! inTiny ) {
  257.     
  258.         if ( RandomBool() ) 
  259.             mNodes.MoveEdge( theNode1, theNode2, inPreserveLength );
  260.         else
  261.             mNodes.MoveEdge( theNode2, theNode1, inPreserveLength );
  262.             
  263.         return true;
  264.     }
  265.     else {
  266.     
  267.         if ( RandomBool() )
  268.             return mNodes.TinyMoveEdge( theNode1, theNode2 );
  269.         else
  270.             return mNodes.TinyMoveEdge( theNode2, theNode1 );
  271.     }
  272. }
  273.  
  274. // ---------------------------------------------------------------------------
  275. //        • TwoEdgeMutation    (PRIVATE)
  276. //
  277. //          Called by:    CGraphDrawing::Mutate
  278. // ---------------------------------------------------------------------------
  279.  
  280. Boolean
  281. CGraphDrawing::TwoEdgeMutation( )
  282. {
  283.     CNodePtr    theNode1, theNode2, theNode3;
  284.     
  285.     if ( mEdgeCount < 2 ) return false;
  286.     
  287.     if ( ThreeConnectedNodes( theNode1, theNode2, theNode3 ) ) {
  288.         if ( RandomBool() )
  289.                 mNodes.Move3ConnectedNodes( theNode1, theNode2, theNode3 );
  290.         else    mNodes.Move3ConnectedNodes( theNode2, theNode1, theNode3 );
  291.     } else
  292.         mNodes.MoveEdge( theNode1, theNode2, true );
  293.         
  294.     return true;
  295. }
  296.  
  297. // ---------------------------------------------------------------------------
  298. //        • ThreeConnectedNodes    (PRIVATE)
  299. //
  300. //          Called by:    CGraphDrawing::TwoEdgeMutation
  301. //                        CGraphDrawing::ThreeNodeCrossover
  302. // ---------------------------------------------------------------------------
  303.  
  304. Boolean
  305. CGraphDrawing::ThreeConnectedNodes( 
  306.     CNodePtr    &outNode1,
  307.     CNodePtr    &outNode2,
  308.     CNodePtr    &outNode3    )
  309. {
  310.     CEdge        *theEdge;
  311.     Boolean        theFound = false;
  312.  
  313.     // First we pick a random edge...
  314.     Int16    theEdgeIndex = FastRandom( mEdgeCount );
  315.     theEdge = &mEdges[ theEdgeIndex ];
  316.     
  317.     // ...which gives us already 2 of 3 needed nodes
  318.     theEdge -> GetEdgeNodes( outNode1, outNode2 );
  319.     
  320.     // We still need one node which is connected to either
  321.     // outNode1 or outNode2 by an edge. Let's see if we can find one.
  322.  
  323.     if ( mEdgeCount > 1 ) {
  324.     
  325.         EdgeVector::const_iterator    
  326.             theLast = mEdges.begin() + RangedRdm( 0, mEdgeCount - 2 );        
  327.         EdgeVector::const_iterator
  328.             theIter = theLast + 1;
  329.         
  330.         while ( (! theFound ) && ( theIter != theLast ) ) {
  331.             
  332.             if ( ( theIter != theEdge ) &&
  333.                  ( theIter -> OtherNode( outNode1, outNode3 ) ||
  334.                    theIter -> OtherNode( outNode2, outNode3 )) )
  335.                    theFound = true;
  336.             else {
  337.                 ++theIter;
  338.                 if ( theIter == mEdges.end() )
  339.                     theIter = mEdges.begin();
  340.             }
  341.         }
  342.     }
  343.  
  344.     return theFound;
  345. }
  346.  
  347. // ---------------------------------------------------------------------------
  348. //        • ThreeNodeCrossover
  349. //
  350. //          Called by:    CPopulation::DoCrossover
  351. // ---------------------------------------------------------------------------
  352.  
  353. void
  354. CGraphDrawing::ThreeNodeCrossover( 
  355.     CGraphPtr    inCrosser2 )
  356. {
  357.     CNodePtr    theNode11, theNode12, theNode13,
  358.                 theNode21, theNode22, theNode23;
  359.     Boolean        theGotThree;
  360.     Int16        theNbr1, theNbr2, theNbr3 = 0;
  361.     Point        thePos11, thePos12, thePos13,
  362.                 thePos21, thePos22, thePos23;
  363.  
  364.     if ( mEdgeCount < 1 ) return;
  365.  
  366.     theGotThree = ThreeConnectedNodes( theNode11, theNode12, theNode13 );
  367.     
  368.     theNbr1 = theNode11 -> GetNodeNbr();
  369.     theNbr2 = theNode12 -> GetNodeNbr();
  370.         
  371.     theNode11 -> GetNodePos( thePos11 );
  372.     theNode12 -> GetNodePos( thePos12 );
  373.  
  374.     theNode21 = inCrosser2 -> mNodes.GetNodePtrByNbr( theNbr1 );
  375.     theNode22 = inCrosser2 -> mNodes.GetNodePtrByNbr( theNbr2 );
  376.         
  377.     theNode21 -> GetNodePos( thePos21 );
  378.     theNode22 -> GetNodePos( thePos22 );
  379.     
  380.     if ( theGotThree ) {
  381.         theNbr3        =  theNode13 -> GetNodeNbr();
  382.         theNode13    -> GetNodePos( thePos13 );
  383.         theNode23    =  inCrosser2 -> mNodes.GetNodePtrByNbr( theNbr3 );
  384.         theNode23    -> GetNodePos( thePos23 );
  385.     }
  386.         
  387.     mEvaluationNeeded =
  388.         mNodes.ThreeNodeCrossover(    theNbr1, theNbr2, theNbr3,
  389.                                     thePos21, thePos22, thePos23 );
  390.                                
  391.     inCrosser2 -> mEvaluationNeeded =
  392.         mNodes.ThreeNodeCrossover(    theNbr1, theNbr2, theNbr3,
  393.                                     thePos11, thePos12, thePos13 );
  394.  
  395. }
  396.  
  397. // ---------------------------------------------------------------------------
  398. //        • RectCrossover
  399. //
  400. //          Called by:    CPopulation::DoCrossover
  401. //                        CPopulation::DoRectCrossover
  402. // ---------------------------------------------------------------------------
  403.  
  404. void
  405. CGraphDrawing::RectCrossover( 
  406.     const Rect             &inSourceRect,
  407.     const Rect            &inDestRect, 
  408.     const CGraphDrawing &inBaseGraph,
  409.     const CGraphDrawing &inRectGraph )
  410. {
  411.     mNodes.RectCrossover( inSourceRect, inDestRect, 
  412.                       *(inBaseGraph.GetNodes()) , 
  413.                       *(inRectGraph.GetNodes())   );
  414.     
  415.     mEvaluationNeeded = true;
  416. }
  417.  
  418. // ---------------------------------------------------------------------------
  419. //        • Evaluate        (PRIVATE)
  420. //
  421. //          Called by:    CGraphDrawing::GetFitness
  422. // ---------------------------------------------------------------------------
  423.  
  424. void
  425. CGraphDrawing::Evaluate( Int32 inCurLeastCrossings )
  426. {
  427.     Int32   theCrossings;
  428.  
  429.     if ( mCrossMemo )
  430.         theCrossings = SmarterCountSect();
  431.     else
  432.         theCrossings = SimpleCountSect();
  433.  
  434.     // We don't waste time on measuring more details, if the
  435.     // drawing has more crossings than our current best drawing...
  436.     // AND if we treat minimizing crossings as our primary goal.
  437.  
  438.     if ( CFitness::CrossingsRule && (theCrossings > inCurLeastCrossings))
  439.         mFitness.SetMinDistance( 0L );
  440.     else {
  441.         CountEdgeLengths();
  442.         mNodes.BruteForceClosestPairs( mFitness );
  443.     }
  444.  
  445.     mEvaluationNeeded = false;
  446. }
  447.  
  448. // ---------------------------------------------------------------------------
  449. //        • DrawEdges
  450. //
  451. //          Called by:    CGraphPane::DrawEdges
  452. // ---------------------------------------------------------------------------
  453.  
  454. void
  455. CGraphDrawing::DrawEdges( Int16 inOneOneXY, Int16 inSquareSize) const
  456. {
  457.     EdgeVector::const_iterator    theIter = mEdges.begin();
  458.  
  459.     while ( theIter != mEdges.end() ) {
  460.         theIter -> Draw( inOneOneXY, inSquareSize );
  461.         ++theIter;
  462.     }
  463. }
  464.  
  465. // ---------------------------------------------------------------------------
  466. //        • SimpleCountSect    (PRIVATE)
  467. //
  468. //          Called by:    CGraphDrawing::Evaluate
  469. // ---------------------------------------------------------------------------
  470. //    The brute force way of counting the intersections in a graph.
  471.  
  472. Int32
  473. CGraphDrawing::SimpleCountSect( )
  474. {
  475.     Int32    theCount = 0L;
  476.  
  477.     if ( mEdgeCount > 1 ) {
  478.  
  479.         EdgeVector::const_iterator   the1st;
  480.         EdgeVector::const_iterator   the2nd;
  481.     
  482.         for ( the1st = mEdges.begin();
  483.               the1st != mEdges.end()-1; ++the1st )
  484.             for ( the2nd = the1st + 1;
  485.                   the2nd != mEdges.end(); ++the2nd ) {
  486.                   
  487.                 if ( the1st -> Intersects( *the2nd ) )
  488.                     theCount++;
  489.             }
  490.     }
  491.  
  492.     mFitness.SetCrossings( theCount );
  493.     
  494.     return theCount;
  495. }
  496.  
  497. // ---------------------------------------------------------------------------
  498. //        • SmarterCountSect    (PRIVATE)
  499. //
  500. //          Called by:    CGraphDrawing::Evaluate
  501. // ---------------------------------------------------------------------------
  502. //    Counting the intersections using the "cross memory".
  503.  
  504. Int32
  505. CGraphDrawing::SmarterCountSect( )
  506. {
  507.     Int32    theCount = 0L;
  508.     
  509.     if ( mEdgeCount > 1 ) {
  510.     
  511.         EdgeVector::const_iterator    the1st;
  512.         EdgeVector::const_iterator    the2nd;
  513.         
  514.         if ( mMemoryIsGarbage ) {
  515.  
  516.             // The following is like the brute force method used
  517.             // by SimpleSectCount, but here we store the crossing
  518.             // facts to our "cross memory"
  519.  
  520.             mCrossMemo -> ResetCrossTotal();
  521.             mCrossMemo -> ResetScanner();
  522.             
  523.             for (     the1st = mEdges.begin();
  524.                     the1st != mEdges.end() - 1; 
  525.                     ++the1st ) {
  526.                 for (    the2nd = the1st + 1;
  527.                         the2nd != mEdges.end(); 
  528.                         ++the2nd ) {
  529.                     
  530.                     mCrossMemo -> SetCrossFact( 
  531.                                     the1st -> Intersects( *the2nd ) );
  532.                     mCrossMemo -> AdvanceScanner();
  533.                 }
  534.             }
  535.             
  536.             mMemoryIsGarbage = false;
  537.         }
  538.         else {
  539.         
  540.             // Here we use the facts stored in the "cross memory"
  541.             // and only update the crossing facts for moved edges.
  542.             
  543.             Boolean theMover1;
  544.             
  545.             mCrossMemo -> ResetScanner();
  546.         
  547.             for (     the1st = mEdges.begin();
  548.                     the1st != mEdges.end() - 1;
  549.                     ++the1st ) {
  550.                 theMover1 = the1st -> HasMoved();
  551.                 for (    the2nd = the1st + 1;
  552.                         the2nd != mEdges.end();
  553.                         ++the2nd ) {
  554.                         
  555.                     if ( theMover1 || the2nd -> HasMoved() )
  556.                         mCrossMemo -> SetCrossFactByFlipping(
  557.                                         the1st -> Intersects( *the2nd ) );
  558.                                         
  559.                     mCrossMemo -> AdvanceScanner();
  560.                 }
  561.             }
  562.         }
  563.  
  564.         mNodes.ResetAll( );        // Set all nodes as non-movers
  565.  
  566.         theCount = mCrossMemo -> GetCrossTotal();
  567.     }
  568.  
  569.     mFitness.SetCrossings( theCount );
  570.     
  571.     return theCount;
  572. }
  573.  
  574. // ---------------------------------------------------------------------------
  575. //        • CountEdgeLengths
  576. //
  577. //          Called by:    CGraphDrawing::Evaluate
  578. // ---------------------------------------------------------------------------
  579.  
  580. void
  581. CGraphDrawing::CountEdgeLengths( )
  582. {
  583.     Int16    theLength,
  584.             theMin = max_Int16;
  585.     Int32    theDeviationSum = 0;
  586.     
  587.     EdgeVector::iterator    theIter;
  588.  
  589.     for ( theIter = mEdges.begin(); theIter != mEdges.end(); ++theIter ) {
  590.         theLength = theIter -> SetLength();
  591.         if ( theLength < theMin )
  592.             theMin = theLength;
  593.     }
  594.  
  595.     for ( theIter = mEdges.begin(); theIter != mEdges.end(); ++theIter ) {
  596.         theLength = theIter -> GetLength();
  597.         theDeviationSum += (theLength == theMin) ?
  598.                            theMin : theLength - (theMin + 1);
  599.     }
  600.  
  601.     mFitness.SetEdgeStuff( theDeviationSum );
  602. }
  603.  
  604. // ---------------------------------------------------------------------------
  605. //        • BestCopy
  606. //
  607. //          Called by:    CPopulation::InitBestEver
  608. //                        CPopulation::Evaluate
  609. // ---------------------------------------------------------------------------
  610. //  This copy routine is used for the "best ever" graph drawing
  611.  
  612. void
  613. CGraphDrawing::BestCopy( 
  614.     const CGraphDrawing & inGD,
  615.     Boolean    inFirstTime )
  616. {
  617.     mFitness    = inGD.mFitness;
  618.     mNodes        = inGD.mNodes;
  619.  
  620.     if ( inFirstTime ) {
  621.         mEdgeCount             = inGD.mEdgeCount;
  622.         mEvaluationNeeded    = inGD.mEvaluationNeeded;
  623.         CopyEdges( inGD );
  624.     }
  625. }
  626.  
  627. // ---------------------------------------------------------------------------
  628. //        • RuntimeCopy
  629. //
  630. //          Called by:    CPopulation::DoSelection
  631. //                        CPopulation::DoRectCrossover
  632. // ---------------------------------------------------------------------------
  633. //  Copy all the fields that change during the iterations.
  634. //  Note that for example the edge array doesn't get copied. 
  635.  
  636. void
  637. CGraphDrawing::RuntimeCopy( 
  638.     const CGraphDrawing & inGD,
  639.     Boolean inCopyCrossMemory )
  640. {
  641.     mFitness            = inGD.mFitness;
  642.     mEvaluationNeeded    = inGD.mEvaluationNeeded;
  643.     mMemoryIsGarbage    = inGD.mMemoryIsGarbage;
  644.     mSelectionOriginal    = inGD.mSelectionOriginal;
  645.     
  646.     mNodes.mNodesArray    = inGD.mNodes.mNodesArray;
  647.     
  648.     if ( mCrossMemo ) {
  649.         if ( inCopyCrossMemory )
  650.             *mCrossMemo = *(inGD.mCrossMemo);
  651.         else
  652.             mMemoryIsGarbage = true;
  653.     }
  654. }
  655.  
  656. // ---------------------------------------------------------------------------
  657. //        • CopyEdges        (PRIVATE)
  658. //
  659. //          Called by:    CGraphDrawing::BestCopy
  660. // ---------------------------------------------------------------------------
  661. //  Because of the pointers to nodes we can not simply do this by writing
  662. //            mEdges = inGD.mEdges; (Trust me, I tried... :-)
  663.  
  664. void        
  665. CGraphDrawing::CopyEdges( const CGraphDrawing & inGD)
  666. {
  667.     Int16    theEdgeDex, theNbr1, theNbr2, theCopySize;
  668.     
  669.     if ( mEdges.size() != (theCopySize = inGD.mEdges.size())) {
  670.         mEdges.erase ( mEdges.begin(), mEdges.end() );
  671.         mEdges.reserve( theCopySize );
  672.  
  673.         for ( theEdgeDex = 1; theEdgeDex <= mEdgeCount; ++theEdgeDex )
  674.             mEdges.push_back( CEdge() );
  675.     }
  676.  
  677.     for ( theEdgeDex = 0; theEdgeDex <= mEdgeCount-1; ++theEdgeDex ) {
  678.  
  679.         inGD.mEdges[ theEdgeDex ].GetNodeNumbers( theNbr1, theNbr2 );
  680.         mEdges[ theEdgeDex ].Set( mNodes.GetNodePtrByNbr( theNbr1 ), 
  681.                                   mNodes.GetNodePtrByNbr( theNbr2 )  );
  682.     }
  683. }
  684.